/*
 * Copyright (c) 2025 Industrial Software Feature Database
 */
package com.comac.ins.isfd.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ArrayUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.comac.ins.common.core.utils.SpringUtils;
import com.comac.ins.common.core.utils.StringUtils;
import com.comac.ins.isfd.constant.MongoDataConstant;
import com.comac.ins.isfd.constant.enums.MetaDataElementDataTypeEnum;
import com.comac.ins.isfd.core.IMaterialGetService;
import com.comac.ins.isfd.core.impl.MaterialGetFromMongoService;
import com.comac.ins.isfd.domain.IsfdMetadata;
import com.comac.ins.isfd.domain.vo.IsfdTreeNodeVo;
import com.comac.ins.isfd.domain.vo.MaterialCountObjectVo;

import com.comac.ins.isfd.mapper.IsfdMetadataMapper;
import com.comac.ins.isfd.service.IMaterialInfoService;
import lombok.RequiredArgsConstructor;
import org.bson.Document;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 材料库信息Service业务层处理
 *
 * @author Lion Li
 * @date 2024-06-07
 */
@RequiredArgsConstructor
@Service
public class MaterialInfoServiceImpl implements IMaterialInfoService, MongoDataConstant {

    private static final String DB_NAME = "comac_db";

    private final IsfdMetadataMapper isfdMetadataMapper;

    /**
     * 按照series查询basic
     *
     * @param businessScenarioNo 业务场景
     * @param type               类型
     * @param series             series
     * @return 材料库信息
     */
    @Override
    public Map<String, Object> queryBasicBySeries(String businessScenarioNo, String type, String series) {
        //树形结构前两层在元数据isfd_metadata表中查询
        IsfdMetadata isfdMetadata = getIsfdMetadata(businessScenarioNo, type);
        Map<String, Object> result = getBasicBySeries(isfdMetadata, series);
        return result;
    }

    /**
     * 按类型统计所有材料库信息
     *
     * @param businessScenarioNos 业务场景
     * @param types               类型
     * @return 材料库信息
     */
    @Override
    public List<MaterialCountObjectVo> countByMaterialType(String[] businessScenarioNos, String[] types) {
        List<MaterialCountObjectVo> result = new ArrayList<>();
        List<IsfdMetadata> isfdMetadataList = getIsfdMetadata(businessScenarioNos, types);
        isfdMetadataList.forEach(isfdMetadata -> {
            IMaterialGetService materialGetService = getMaterialGetServiceByType(isfdMetadata);
            List<MaterialCountObjectVo> countObjectList = materialGetService.countByType(isfdMetadata);
            result.addAll(countObjectList);
        });
        return result;
    }

    private List<IsfdMetadata> getIsfdMetadata(String[] businessScenarioNos, String[] types) {
        LambdaQueryWrapper<IsfdMetadata> lambdaQueryWrapper = buildQueryWrapper(businessScenarioNos, types);
        List<IsfdMetadata> isfdMetadataList = isfdMetadataMapper.selectList(lambdaQueryWrapper);
        return isfdMetadataList;
    }

    /**
     * @param businessScenarioNos 业务场景
     * @param types               类型
     * @param detail
     * @return
     * @description
     */
    @Override
    public IsfdTreeNodeVo queryTree(String[] businessScenarioNos, String[] types, Boolean detail) {
        //树形结构前两层在元数据isfd_metadata表中查询
        List<IsfdMetadata> isfdMetadataList = getIsfdMetadata(businessScenarioNos, types);
        IsfdTreeNodeVo result = generateTree(isfdMetadataList, detail);
        return result;
    }

    /**
     * 按照树形查询材料库信息详情
     *
     * @param businessScenarioNo 业务场景
     * @param type               类型
     * @param series             series
     * @return 材料库信息
     */
    @Override
    public List<Map<String, Object>> queryTreeNodeDetail(String businessScenarioNo, String type, String series) {
        IsfdMetadata isfdMetadata = getIsfdMetadata(businessScenarioNo, type);
        List<Map<String, Object>> result = getIsfdMetadata(isfdMetadata, series);
        return result;
    }

    private IsfdMetadata getIsfdMetadata(String businessScenarioNo, String type) {
        //树形结构前两层在元数据isfd_metadata表中查询
        LambdaQueryWrapper<IsfdMetadata> lambdaQueryWrapper = buildQueryWrapper(businessScenarioNo, type);
        IsfdMetadata isfdMetadata = isfdMetadataMapper.selectOne(lambdaQueryWrapper);
        return isfdMetadata;
    }

    private LambdaQueryWrapper<IsfdMetadata> buildQueryWrapper(String[] businessScenarioNos, String[] types) {
        LambdaQueryWrapper<IsfdMetadata> lqw = Wrappers.lambdaQuery();
        lqw.eq(IsfdMetadata::getElementDataType, MetaDataElementDataTypeEnum.MATERIAL.getValue());
        lqw.in(ArrayUtil.isNotEmpty(businessScenarioNos), IsfdMetadata::getBusinessScenarioNo, businessScenarioNos);
        lqw.in(ArrayUtil.isNotEmpty(types), IsfdMetadata::getTableName, types);
        return lqw;
    }

    private LambdaQueryWrapper<IsfdMetadata> buildQueryWrapper(String businessScenarioNo, String type) {
        LambdaQueryWrapper<IsfdMetadata> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(businessScenarioNo), IsfdMetadata::getBusinessScenarioNo, businessScenarioNo);
        lqw.eq(StringUtils.isNotBlank(type), IsfdMetadata::getTableName, type);
        return lqw;
    }

    private IsfdTreeNodeVo generateTree(List<IsfdMetadata> isfdMetadataList, Boolean detail) {
        IsfdTreeNodeVo<IsfdTreeNodeVo> rootNode = new IsfdTreeNodeVo("-1", "root", "root", null);

        Map<String, List<IsfdMetadata>> stringListMap = isfdMetadataList.stream()
            .collect(Collectors.groupingBy(IsfdMetadata::getBusinessScenarioNo));
        if (CollectionUtil.isEmpty(stringListMap)) {
            return rootNode;
        }
        rootNode.setChildren(new ArrayList<>());
        stringListMap.forEach((key, list) -> {
            IsfdTreeNodeVo<IsfdTreeNodeVo> node = generateFirstNode(key, list);
            node.setChildren(generateSecondAndOtherNode(list, detail));
            rootNode.getChildren().add(node);
        });
        return rootNode;
    }

    /***
     * @description 第一层按照业务应用场景businessScenarioNo来构建，例如：(1-结构CAE)
     * @param key
     * @param list
     * @return
     */
    @NotNull
    private IsfdTreeNodeVo generateFirstNode(String key, List<IsfdMetadata> list) {
        IsfdTreeNodeVo node = new IsfdTreeNodeVo();
        node.setNodeId(key);
        node.setNodeName(list.get(0).getBusinessScenarioName());
        node.setChildren(new ArrayList<IsfdTreeNodeVo>());
        return node;
    }

    /***
     * @description 第二层按照相同businessScenarioNo下的元数据构建，第三层后按照类型自行实现
     * @param isfdMetadataList
     * @return
     */
    @NotNull
    private List<IsfdTreeNodeVo> generateSecondAndOtherNode(List<IsfdMetadata> isfdMetadataList, Boolean detail) {
        List<IsfdTreeNodeVo> result = new ArrayList<>();
        isfdMetadataList.forEach(isfdMetadata -> {
            IsfdTreeNodeVo childNode = generateSecondNode(isfdMetadata);
            childNode.setChildren(generateOtherTreeNode(isfdMetadata, detail));
            result.add(childNode);
        });
        return result;
    }

    /***
     * @description 第二层按照相同businessScenarioNo下的元数据构建
     * @param isfdMetadata
     * @return
     */
    @NotNull
    private IsfdTreeNodeVo generateSecondNode(IsfdMetadata isfdMetadata) {
        IsfdTreeNodeVo childNode = new IsfdTreeNodeVo();
        childNode.setNodeId(isfdMetadata.getId().toString());
        childNode.setNodeType(isfdMetadata.getTableName());
        childNode.setNodeName(isfdMetadata.getTableDescription());
        return childNode;
    }

    /***
     * @description 调用实现接口组成三级之后的树形结构
     * @param isfdMetadata
     * @return
     */
    private List<Map<String, Object>> generateOtherTreeNode(IsfdMetadata isfdMetadata, Boolean detail) {
        if (null == isfdMetadata || isfdMetadata.getStorageType().isBlank()) {
            return new ArrayList<>();
        }
        IMaterialGetService materialGetService = getMaterialGetServiceByType(isfdMetadata);
        List<Map<String, Object>> otherTreeNode = materialGetService.generateTreeNode(isfdMetadata, detail);
        return otherTreeNode;
    }

    /***
     * @description 调用实现接口查询详情
     * @param isfdMetadata
     * @return
     */
    private List<Map<String, Object>> getIsfdMetadata(IsfdMetadata isfdMetadata, String series) {
        if (null == isfdMetadata || isfdMetadata.getStorageType().isBlank()) {
            return new ArrayList<>();
        }
        IMaterialGetService materialGetService = getMaterialGetServiceByType(isfdMetadata);
        List<Map<String, Object>> treeNodeDetail = materialGetService.getTreeNodeDetail(isfdMetadata, new String[]{series});
        return treeNodeDetail;
    }

    /***
     * @description 调用getBasicBySeriesGroupByBasic实现getBasicBySeries，使用数据库分组
     * @param isfdMetadata
     * @return
     */
    private Map<String, Object> getBasicBySeries(IsfdMetadata isfdMetadata, String series) {
        if (null == isfdMetadata || isfdMetadata.getStorageType().isBlank()) {
            return new HashMap<>();
        }
        Map<String, Object> params = new HashMap<>();
        params.put(BASIC_SERIES, series);
        MaterialGetFromMongoService materialGetService = (MaterialGetFromMongoService) getMaterialGetServiceByType(isfdMetadata);
        return materialGetService.getBasicBySeriesGroupByBasic(isfdMetadata, series);
        //List<Map<String, Object>> dataList = materialGetService.getNodeDataByParams(isfdMetadata, params);
        //return convertBasicDataBySeries(dataList, series);
    }

    /**
     * 将查询的basic数据结构转换为字典列表结构，并去重
     *
     * @param dataList
     * @param series
     * @return
     */
    private Map<String, Object> convertBasicDataBySeries(List<Map<String, Object>> dataList, String series) {
        Map<String, Object> result = new HashMap<>();
        if (CollectionUtil.isEmpty(dataList)) {
            return result;
        }
        result.put(SERIES, series);
        result.put(BASIS, new HashSet<>());
        result.put(SPECIFICATION, new HashSet<>());
        result.put(TEMPER, new HashSet<>());
        result.put(THICKNESS, new HashSet<>());
        result.put(FORM, new HashSet<>());
        dataList.stream().forEach(m -> {
            if (CollectionUtil.isNotEmpty(m)) {
                //m.put(ID, m.get(ID).toString());
                if (m.containsKey(BASIC)) {
                    Document basic = (Document) m.get(BASIC);
                    addDataFromBasicDocument(result, basic, FORM);
                    addDataFromBasicDocument(result, basic, BASIS);
                    addDataFromBasicDocument(result, basic, SPECIFICATION);
                    addDataFromBasicDocument(result, basic, TEMPER);
                    addDataFromBasicDocument(result, basic, THICKNESS);
                }
            }
        });
        return result;
    }

    private void addDataFromBasicDocument(Map<String, Object> result, Document document, String key) {
        String value = "";
        if (document.get(key) instanceof List) {
            value = String.join(",", document.getList(key, String.class));
        } else {
            value = document.getString(key);
        }
        ((Set) result.get(key)).add(value.trim());
    }

    @NotNull
    private IMaterialGetService getMaterialGetServiceByType(IsfdMetadata isfdMetadata) {
        return SpringUtils.context().getBean(isfdMetadata.getStorageType(), IMaterialGetService.class);
    }


//    /***
//     * @description
//     * @param type
//     * @param _id
//     * @return Map<String, Object>
//     */
//    @Override
//    public Map<String, Object> queryById(String type, String _id) {
//        Map<String, Object> result = mongoPlusMapper.getById("comac_db", type, _id);
//        serizlizedId(result);
//        return result;
//    }
//
//    /***
//     * @description 分页查询
//     * @param bo
//     * @param pageQuery 分页参数
//     * @return TableDataInfo<Map < String, Object>>
//     */
//    @Override
//    public TableDataInfo<Map<String, Object>> queryPageList(MaterialInfoBo bo, PageQuery pageQuery) {
//        QueryChainWrapper wrapper = getQueryChainWrapper(bo);
//        PageResult<Map<String, Object>> materials = mongoPlusMapper.page(DB_NAME, bo.getType(),
//            new PageParam(pageQuery.getPageNum(), pageQuery.getPageSize()), wrapper);
//        //处理_id问题
//        serizlizedId(materials.getContentData());
//        return this.build(materials);
//    }
//
//    /***
//     * @description
//     * @param materials
//     * @return
//     */
//    private void serizlizedId(List<Map<String, Object>> materials) {
//        if (CollectionUtil.isEmpty(materials)) {
//            return;
//        }
//        //处理_id问题
//        materials.stream().map(m -> {
//            return serizlizedId(m);
//        }).collect(Collectors.toList());
//    }
//
//    private Map<String, Object> serizlizedId(Map<String, Object> m) {
//        if (CollectionUtil.isNotEmpty(m) && m.containsKey("_id")) {
//            m.put("_id", m.get("_id").toString());
//        }
//        return m;
//    }
//
//    @Override
//    public List<Map<String, Object>> queryList(MaterialInfoBo bo) {
//        QueryChainWrapper wrapper = getQueryChainWrapper(bo);
//        List<Map<String, Object>> materials = mongoPlusMapper.list(DB_NAME, bo.getType(),
//            wrapper);
//        //处理_id问题
//        serizlizedId(materials);
//        return materials;
//    }
//
//    /**
//     * @param type 材料库type
//     * @param bo   材料库信息
//     * @return
//     */
//    @Override
//    public Boolean insertByBo(String type, JSONObject bo) {
//        return mongoPlusMapper.save(DB_NAME, type,
//            bo.toBean(Map.class));
//    }
//
//    /**
//     * @param type 材料库type
//     * @param bo   材料库信息
//     * @return
//     */
//    @Override
//    public Boolean updateByBo(String type, JSONObject bo) {
//        return mongoPlusMapper.updateById(DB_NAME, type,
//            bo.toBean(Map.class));
//    }
//
//
//    /**
//     * @param type    材料库type
//     * @param ids     待删除的主键集合
//     * @param isValid 是否进行有效性校验
//     * @return
//     */
//    @Override
//    public Boolean deleteWithValidByIds(String type, Collection<String> ids, Boolean isValid) {
//        if (isValid) {
//            //TODO 做一些业务上的校验,判断是否需要校验
//        }
//        return mongoPlusMapper.removeBatchByIds(DB_NAME, type, ids);
//    }
//
//
//    /***
//     * @description
//     * @param bo
//     * @return
//     */
//    private QueryChainWrapper getQueryChainWrapper(MaterialInfoBo bo) {
//        //wrapper
//        QueryChainWrapper wrapper = new QueryWrapper();
//        switch (bo.getType()) {
//            case "comp_material":
//                wrapper.eq(null != bo.getP_index(), "p_index", bo.getP_index());
//                break;
//            case "mat_material":
//                if (StringUtils.isNotBlank(bo.getBasic())) {
//                    MatMaterialBasicBo basic = JSONUtil.toBean(bo.getBasic(), MatMaterialBasicBo.class);
//                    wrapper.like(StringUtils.isNotBlank(basic.getSeries()), "basic.series", basic.getSeries())
//                        .like(StringUtils.isNotBlank(basic.getSpecification()), "basic.specification", basic.getSpecification())
//                        .like(StringUtils.isNotBlank(basic.getBasis()), "basic.basis", basic.getBasis())
//                        .like(StringUtils.isNotBlank(basic.getTemper()), "basic.temper", basic.getTemper())
//                        .like(StringUtils.isNotBlank(basic.getOrigin_thickness()), "basic.origin_thickness", basic.getOrigin_thickness())
//                        .like(StringUtils.isNotBlank(basic.getThickness()), "basic.thickness", basic.getThickness())
//                        .like(StringUtils.isNotBlank(basic.getType()), "basic.type", basic.getType());
//                }
//                break;
//            default:
//                break;
//        }
//        return wrapper;
//    }
//
//    /**
//     * @param page
//     * @param <T>
//     * @return
//     */
//    public <T> TableDataInfo<T> build(PageResult<T> page) {
//        TableDataInfo<T> rspData = new TableDataInfo<>();
//        rspData.setCode(HttpStatus.HTTP_OK);
//        rspData.setMsg("查询成功");
//        rspData.setRows(page.getContentData());
//        rspData.setTotal(page.getTotalSize());
//        return rspData;
//    }

}
